home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 16 Instancing and Frustum Culling / InstancingAndCulling / InstancingAndCullingApp.cpp < prev   
Encoding:
C/C++ Source or Header  |  2016-03-02  |  35.7 KB  |  1,022 lines

  1. //***************************************************************************************
  2. // InstancingAndCullingApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "../../Common/Camera.h"
  10. #include "FrameResource.h"
  11.  
  12. using Microsoft::WRL::ComPtr;
  13. using namespace DirectX;
  14. using namespace DirectX::PackedVector;
  15.  
  16. #pragma comment(lib, "d3dcompiler.lib")
  17. #pragma comment(lib, "D3D12.lib")
  18.  
  19. const int gNumFrameResources = 3;
  20.  
  21. // Lightweight structure stores parameters to draw a shape.  This will
  22. // vary from app-to-app.
  23. struct RenderItem
  24. {
  25.     RenderItem() = default;
  26.     RenderItem(const RenderItem& rhs) = delete;
  27.  
  28.     // World matrix of the shape that describes the object's local space
  29.     // relative to the world space, which defines the position, orientation,
  30.     // and scale of the object in the world.
  31.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  32.  
  33.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  34.  
  35.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  36.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  37.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  38.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  39.     int NumFramesDirty = gNumFrameResources;
  40.  
  41.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  42.     UINT ObjCBIndex = -1;
  43.  
  44.     Material* Mat = nullptr;
  45.     MeshGeometry* Geo = nullptr;
  46.  
  47.     // Primitive topology.
  48.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  49.  
  50.     BoundingBox Bounds;
  51.     std::vector<InstanceData> Instances;
  52.  
  53.     // DrawIndexedInstanced parameters.
  54.     UINT IndexCount = 0;
  55.     UINT InstanceCount = 0;
  56.     UINT StartIndexLocation = 0;
  57.     int BaseVertexLocation = 0;
  58. };
  59.  
  60. class InstancingAndCullingApp : public D3DApp
  61. {
  62. public:
  63.     InstancingAndCullingApp(HINSTANCE hInstance);
  64.     InstancingAndCullingApp(const InstancingAndCullingApp& rhs) = delete;
  65.     InstancingAndCullingApp& operator=(const InstancingAndCullingApp& rhs) = delete;
  66.     ~InstancingAndCullingApp();
  67.  
  68.     virtual bool Initialize()override;
  69.  
  70. private:
  71.     virtual void OnResize()override;
  72.     virtual void Update(const GameTimer& gt)override;
  73.     virtual void Draw(const GameTimer& gt)override;
  74.  
  75.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  76.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  77.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  78.  
  79.     void OnKeyboardInput(const GameTimer& gt);
  80.     void AnimateMaterials(const GameTimer& gt);
  81.     void UpdateInstanceData(const GameTimer& gt);
  82.     void UpdateMaterialBuffer(const GameTimer& gt);
  83.     void UpdateMainPassCB(const GameTimer& gt);
  84.  
  85.     void LoadTextures();
  86.     void BuildRootSignature();
  87.     void BuildDescriptorHeaps();
  88.     void BuildShadersAndInputLayout();
  89.     void BuildSkullGeometry();
  90.     void BuildPSOs();
  91.     void BuildFrameResources();
  92.     void BuildMaterials();
  93.     void BuildRenderItems();
  94.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  95.  
  96.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  97.  
  98. private:
  99.  
  100.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  101.     FrameResource* mCurrFrameResource = nullptr;
  102.     int mCurrFrameResourceIndex = 0;
  103.  
  104.     UINT mCbvSrvDescriptorSize = 0;
  105.  
  106.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  107.  
  108.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  109.  
  110.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  111.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  112.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  113.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  114.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  115.  
  116.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  117.  
  118.     // List of all the render items.
  119.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  120.  
  121.     // Render items divided by PSO.
  122.     std::vector<RenderItem*> mOpaqueRitems;
  123.  
  124.     bool mFrustumCullingEnabled = true;
  125.  
  126.     BoundingFrustum mCamFrustum;
  127.  
  128.     PassConstants mMainPassCB;
  129.  
  130.     Camera mCamera;
  131.  
  132.     POINT mLastMousePos;
  133. };
  134.  
  135. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  136.     PSTR cmdLine, int showCmd)
  137. {
  138.     // Enable run-time memory check for debug builds.
  139. #if defined(DEBUG) | defined(_DEBUG)
  140.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  141. #endif
  142.  
  143.     try
  144.     {
  145.         InstancingAndCullingApp theApp(hInstance);
  146.         if(!theApp.Initialize())
  147.             return 0;
  148.  
  149.         return theApp.Run();
  150.     }
  151.     catch(DxException& e)
  152.     {
  153.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  154.         return 0;
  155.     }
  156. }
  157.  
  158. InstancingAndCullingApp::InstancingAndCullingApp(HINSTANCE hInstance)
  159.     : D3DApp(hInstance)
  160. {
  161. }
  162.  
  163. InstancingAndCullingApp::~InstancingAndCullingApp()
  164. {
  165.     if(md3dDevice != nullptr)
  166.         FlushCommandQueue();
  167. }
  168.  
  169. bool InstancingAndCullingApp::Initialize()
  170. {
  171.     if(!D3DApp::Initialize())
  172.         return false;
  173.  
  174.     // Reset the command list to prep for initialization commands.
  175.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  176.  
  177.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  178.     // so we have to query this information.
  179.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  180.  
  181.     mCamera.SetPosition(0.0f, 2.0f, -15.0f);
  182.  
  183.     LoadTextures();
  184.     BuildRootSignature();
  185.     BuildDescriptorHeaps();
  186.     BuildShadersAndInputLayout();
  187.     BuildSkullGeometry();
  188.     BuildMaterials();
  189.     BuildRenderItems();
  190.     BuildFrameResources();
  191.     BuildPSOs();
  192.  
  193.     // Execute the initialization commands.
  194.     ThrowIfFailed(mCommandList->Close());
  195.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  196.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  197.  
  198.     // Wait until initialization is complete.
  199.     FlushCommandQueue();
  200.  
  201.     return true;
  202. }
  203.  
  204. void InstancingAndCullingApp::OnResize()
  205. {
  206.     D3DApp::OnResize();
  207.  
  208.     mCamera.SetLens(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  209.  
  210.     BoundingFrustum::CreateFromMatrix(mCamFrustum, mCamera.GetProj());
  211. }
  212.  
  213. void InstancingAndCullingApp::Update(const GameTimer& gt)
  214. {
  215.     OnKeyboardInput(gt);
  216.  
  217.     // Cycle through the circular frame resource array.
  218.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  219.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  220.  
  221.     // Has the GPU finished processing the commands of the current frame resource?
  222.     // If not, wait until the GPU has completed commands up to this fence point.
  223.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  224.     {
  225.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  226.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  227.         WaitForSingleObject(eventHandle, INFINITE);
  228.         CloseHandle(eventHandle);
  229.     }
  230.  
  231.     AnimateMaterials(gt);
  232.     UpdateInstanceData(gt);
  233.     UpdateMaterialBuffer(gt);
  234.     UpdateMainPassCB(gt);
  235. }
  236.  
  237. void InstancingAndCullingApp::Draw(const GameTimer& gt)
  238. {
  239.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  240.  
  241.     // Reuse the memory associated with command recording.
  242.     // We can only reset when the associated command lists have finished execution on the GPU.
  243.     ThrowIfFailed(cmdListAlloc->Reset());
  244.  
  245.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  246.     // Reusing the command list reuses memory.
  247.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  248.  
  249.     mCommandList->RSSetViewports(1, &mScreenViewport);
  250.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  251.  
  252.     // Indicate a state transition on the resource usage.
  253.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  254.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  255.  
  256.     // Clear the back buffer and depth buffer.
  257.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  258.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  259.  
  260.     // Specify the buffers we are going to render to.
  261.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  262.  
  263.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  264.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  265.  
  266.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  267.  
  268.     // Bind all the materials used in this scene.  For structured buffers, we can bypass the heap and 
  269.     // set as a root descriptor.
  270.     auto matBuffer = mCurrFrameResource->MaterialBuffer->Resource();
  271.     mCommandList->SetGraphicsRootShaderResourceView(1, matBuffer->GetGPUVirtualAddress());
  272.  
  273.     auto passCB = mCurrFrameResource->PassCB->Resource();
  274.     mCommandList->SetGraphicsRootConstantBufferView(2, passCB->GetGPUVirtualAddress());
  275.  
  276.     // Bind all the textures used in this scene.
  277.     mCommandList->SetGraphicsRootDescriptorTable(3, mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  278.  
  279.     DrawRenderItems(mCommandList.Get(), mOpaqueRitems);
  280.  
  281.     // Indicate a state transition on the resource usage.
  282.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  283.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  284.  
  285.     // Done recording commands.
  286.     ThrowIfFailed(mCommandList->Close());
  287.  
  288.     // Add the command list to the queue for execution.
  289.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  290.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  291.  
  292.     // Swap the back and front buffers
  293.     ThrowIfFailed(mSwapChain->Present(0, 0));
  294.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  295.  
  296.     // Advance the fence value to mark commands up to this fence point.
  297.     mCurrFrameResource->Fence = ++mCurrentFence;
  298.  
  299.     // Add an instruction to the command queue to set a new fence point. 
  300.     // Because we are on the GPU timeline, the new fence point won't be 
  301.     // set until the GPU finishes processing all the commands prior to this Signal().
  302.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  303. }
  304.  
  305. void InstancingAndCullingApp::OnMouseDown(WPARAM btnState, int x, int y)
  306. {
  307.     mLastMousePos.x = x;
  308.     mLastMousePos.y = y;
  309.  
  310.     SetCapture(mhMainWnd);
  311. }
  312.  
  313. void InstancingAndCullingApp::OnMouseUp(WPARAM btnState, int x, int y)
  314. {
  315.     ReleaseCapture();
  316. }
  317.  
  318. void InstancingAndCullingApp::OnMouseMove(WPARAM btnState, int x, int y)
  319. {
  320.     if((btnState & MK_LBUTTON) != 0)
  321.     {
  322.         // Make each pixel correspond to a quarter of a degree.
  323.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  324.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  325.  
  326.         mCamera.Pitch(dy);
  327.         mCamera.RotateY(dx);
  328.     }
  329.  
  330.     mLastMousePos.x = x;
  331.     mLastMousePos.y = y;
  332. }
  333.  
  334. void InstancingAndCullingApp::OnKeyboardInput(const GameTimer& gt)
  335. {
  336.     const float dt = gt.DeltaTime();
  337.  
  338.     if(GetAsyncKeyState('W') & 0x8000)
  339.         mCamera.Walk(20.0f*dt);
  340.  
  341.     if(GetAsyncKeyState('S') & 0x8000)
  342.         mCamera.Walk(-20.0f*dt);
  343.  
  344.     if(GetAsyncKeyState('A') & 0x8000)
  345.         mCamera.Strafe(-20.0f*dt);
  346.  
  347.     if(GetAsyncKeyState('D') & 0x8000)
  348.         mCamera.Strafe(20.0f*dt);
  349.  
  350.     if(GetAsyncKeyState('1') & 0x8000)
  351.         mFrustumCullingEnabled = true;
  352.  
  353.     if(GetAsyncKeyState('2') & 0x8000)
  354.         mFrustumCullingEnabled = false;
  355.  
  356.     mCamera.UpdateViewMatrix();
  357. }
  358.  
  359. void InstancingAndCullingApp::AnimateMaterials(const GameTimer& gt)
  360. {
  361.     
  362. }
  363.  
  364. void InstancingAndCullingApp::UpdateInstanceData(const GameTimer& gt)
  365. {
  366.     XMMATRIX view = mCamera.GetView();
  367.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  368.  
  369.     auto currInstanceBuffer = mCurrFrameResource->InstanceBuffer.get();
  370.     for(auto& e : mAllRitems)
  371.     {
  372.         const auto& instanceData = e->Instances;
  373.  
  374.         int visibleInstanceCount = 0;
  375.  
  376.         for(UINT i = 0; i < (UINT)instanceData.size(); ++i)
  377.         {
  378.             XMMATRIX world = XMLoadFloat4x4(&instanceData[i].World);
  379.             XMMATRIX texTransform = XMLoadFloat4x4(&instanceData[i].TexTransform);
  380.  
  381.             XMMATRIX invWorld = XMMatrixInverse(&XMMatrixDeterminant(world), world);
  382.  
  383.             // View space to the object's local space.
  384.             XMMATRIX viewToLocal = XMMatrixMultiply(invView, invWorld);
  385.  
  386.             // Transform the camera frustum from view space to the object's local space.
  387.             BoundingFrustum localSpaceFrustum;
  388.             mCamFrustum.Transform(localSpaceFrustum, viewToLocal);
  389.  
  390.             // Perform the box/frustum intersection test in local space.
  391.             if((localSpaceFrustum.Contains(e->Bounds) != DirectX::DISJOINT) || (mFrustumCullingEnabled==false))
  392.             {
  393.                 InstanceData data;
  394.                 XMStoreFloat4x4(&data.World, XMMatrixTranspose(world));
  395.                 XMStoreFloat4x4(&data.TexTransform, XMMatrixTranspose(texTransform));
  396.                 data.MaterialIndex = instanceData[i].MaterialIndex;
  397.  
  398.                 // Write the instance data to structured buffer for the visible objects.
  399.                 currInstanceBuffer->CopyData(visibleInstanceCount++, data);
  400.             }
  401.         }
  402.  
  403.         e->InstanceCount = visibleInstanceCount;
  404.  
  405.         std::wostringstream outs;
  406.         outs.precision(6);
  407.         outs << L"Instancing and Culling Demo" <<
  408.             L"    " << e->InstanceCount <<
  409.             L" objects visible out of " << e->Instances.size();
  410.         mMainWndCaption = outs.str();
  411.     }
  412. }
  413.  
  414. void InstancingAndCullingApp::UpdateMaterialBuffer(const GameTimer& gt)
  415. {
  416.     auto currMaterialBuffer = mCurrFrameResource->MaterialBuffer.get();
  417.     for(auto& e : mMaterials)
  418.     {
  419.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  420.         // data changes, it needs to be updated for each FrameResource.
  421.         Material* mat = e.second.get();
  422.         if(mat->NumFramesDirty > 0)
  423.         {
  424.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  425.  
  426.             MaterialData matData;
  427.             matData.DiffuseAlbedo = mat->DiffuseAlbedo;
  428.             matData.FresnelR0 = mat->FresnelR0;
  429.             matData.Roughness = mat->Roughness;
  430.             XMStoreFloat4x4(&matData.MatTransform, XMMatrixTranspose(matTransform));
  431.             matData.DiffuseMapIndex = mat->DiffuseSrvHeapIndex;
  432.  
  433.             currMaterialBuffer->CopyData(mat->MatCBIndex, matData);
  434.  
  435.             // Next FrameResource need to be updated too.
  436.             mat->NumFramesDirty--;
  437.         }
  438.     }
  439. }
  440.  
  441. void InstancingAndCullingApp::UpdateMainPassCB(const GameTimer& gt)
  442. {
  443.     XMMATRIX view = mCamera.GetView();
  444.     XMMATRIX proj = mCamera.GetProj();
  445.  
  446.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  447.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  448.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  449.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  450.  
  451.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  452.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  453.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  454.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  455.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  456.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  457.     mMainPassCB.EyePosW = mCamera.GetPosition3f();
  458.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  459.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  460.     mMainPassCB.NearZ = 1.0f;
  461.     mMainPassCB.FarZ = 1000.0f;
  462.     mMainPassCB.TotalTime = gt.TotalTime();
  463.     mMainPassCB.DeltaTime = gt.DeltaTime();
  464.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  465.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  466.     mMainPassCB.Lights[0].Strength = { 0.8f, 0.8f, 0.8f };
  467.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  468.     mMainPassCB.Lights[1].Strength = { 0.4f, 0.4f, 0.4f };
  469.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  470.     mMainPassCB.Lights[2].Strength = { 0.2f, 0.2f, 0.2f };
  471.  
  472.     auto currPassCB = mCurrFrameResource->PassCB.get();
  473.     currPassCB->CopyData(0, mMainPassCB);
  474. }
  475.  
  476. void InstancingAndCullingApp::LoadTextures()
  477. {
  478.     auto bricksTex = std::make_unique<Texture>();
  479.     bricksTex->Name = "bricksTex";
  480.     bricksTex->Filename = L"../../Textures/bricks.dds";
  481.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  482.         mCommandList.Get(), bricksTex->Filename.c_str(),
  483.         bricksTex->Resource, bricksTex->UploadHeap));
  484.  
  485.     auto stoneTex = std::make_unique<Texture>();
  486.     stoneTex->Name = "stoneTex";
  487.     stoneTex->Filename = L"../../Textures/stone.dds";
  488.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  489.         mCommandList.Get(), stoneTex->Filename.c_str(),
  490.         stoneTex->Resource, stoneTex->UploadHeap));
  491.  
  492.     auto tileTex = std::make_unique<Texture>();
  493.     tileTex->Name = "tileTex";
  494.     tileTex->Filename = L"../../Textures/tile.dds";
  495.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  496.         mCommandList.Get(), tileTex->Filename.c_str(),
  497.         tileTex->Resource, tileTex->UploadHeap));
  498.  
  499.     auto crateTex = std::make_unique<Texture>();
  500.     crateTex->Name = "crateTex";
  501.     crateTex->Filename = L"../../Textures/WoodCrate01.dds";
  502.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  503.         mCommandList.Get(), crateTex->Filename.c_str(),
  504.         crateTex->Resource, crateTex->UploadHeap));
  505.  
  506.     auto iceTex = std::make_unique<Texture>();
  507.     iceTex->Name = "iceTex";
  508.     iceTex->Filename = L"../../Textures/ice.dds";
  509.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  510.         mCommandList.Get(), iceTex->Filename.c_str(),
  511.         iceTex->Resource, iceTex->UploadHeap));
  512.  
  513.     auto grassTex = std::make_unique<Texture>();
  514.     grassTex->Name = "grassTex";
  515.     grassTex->Filename = L"../../Textures/grass.dds";
  516.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  517.         mCommandList.Get(), grassTex->Filename.c_str(),
  518.         grassTex->Resource, grassTex->UploadHeap));
  519.  
  520.     auto defaultTex = std::make_unique<Texture>();
  521.     defaultTex->Name = "defaultTex";
  522.     defaultTex->Filename = L"../../Textures/white1x1.dds";
  523.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  524.         mCommandList.Get(), defaultTex->Filename.c_str(),
  525.         defaultTex->Resource, defaultTex->UploadHeap));
  526.  
  527.     mTextures[bricksTex->Name] = std::move(bricksTex);
  528.     mTextures[stoneTex->Name] = std::move(stoneTex);
  529.     mTextures[tileTex->Name] = std::move(tileTex);
  530.     mTextures[crateTex->Name] = std::move(crateTex);
  531.     mTextures[iceTex->Name] = std::move(iceTex);
  532.     mTextures[grassTex->Name] = std::move(grassTex);
  533.     mTextures[defaultTex->Name] = std::move(defaultTex);
  534. }
  535.  
  536. void InstancingAndCullingApp::BuildRootSignature()
  537. {
  538.     CD3DX12_DESCRIPTOR_RANGE texTable;
  539.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 7, 0, 0);
  540.  
  541.     // Root parameter can be a table, root descriptor or root constants.
  542.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  543.  
  544.     // Perfomance TIP: Order from most frequent to least frequent.
  545.     slotRootParameter[0].InitAsShaderResourceView(0, 1);
  546.     slotRootParameter[1].InitAsShaderResourceView(1, 1);
  547.     slotRootParameter[2].InitAsConstantBufferView(0);
  548.     slotRootParameter[3].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  549.  
  550.     auto staticSamplers = GetStaticSamplers();
  551.  
  552.     // A root signature is an array of root parameters.
  553.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  554.         (UINT)staticSamplers.size(), staticSamplers.data(),
  555.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  556.  
  557.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  558.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  559.     ComPtr<ID3DBlob> errorBlob = nullptr;
  560.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  561.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  562.  
  563.     if(errorBlob != nullptr)
  564.     {
  565.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  566.     }
  567.     ThrowIfFailed(hr);
  568.  
  569.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  570.         0,
  571.         serializedRootSig->GetBufferPointer(),
  572.         serializedRootSig->GetBufferSize(),
  573.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  574. }
  575.  
  576. void InstancingAndCullingApp::BuildDescriptorHeaps()
  577. {
  578.     //
  579.     // Create the SRV heap.
  580.     //
  581.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  582.     srvHeapDesc.NumDescriptors = 7;
  583.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  584.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  585.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  586.  
  587.     //
  588.     // Fill out the heap with actual descriptors.
  589.     //
  590.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  591.  
  592.     auto bricksTex = mTextures["bricksTex"]->Resource;
  593.     auto stoneTex = mTextures["stoneTex"]->Resource;
  594.     auto tileTex = mTextures["tileTex"]->Resource;
  595.     auto crateTex = mTextures["crateTex"]->Resource;
  596.     auto iceTex = mTextures["iceTex"]->Resource;
  597.     auto grassTex = mTextures["grassTex"]->Resource;
  598.     auto defaultTex = mTextures["defaultTex"]->Resource;
  599.  
  600.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  601.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  602.     srvDesc.Format = bricksTex->GetDesc().Format;
  603.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  604.     srvDesc.Texture2D.MostDetailedMip = 0;
  605.     srvDesc.Texture2D.MipLevels = bricksTex->GetDesc().MipLevels;
  606.     srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
  607.     md3dDevice->CreateShaderResourceView(bricksTex.Get(), &srvDesc, hDescriptor);
  608.  
  609.     // next descriptor
  610.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  611.  
  612.     srvDesc.Format = stoneTex->GetDesc().Format;
  613.     srvDesc.Texture2D.MipLevels = stoneTex->GetDesc().MipLevels;
  614.     md3dDevice->CreateShaderResourceView(stoneTex.Get(), &srvDesc, hDescriptor);
  615.  
  616.     // next descriptor
  617.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  618.  
  619.     srvDesc.Format = tileTex->GetDesc().Format;
  620.     srvDesc.Texture2D.MipLevels = tileTex->GetDesc().MipLevels;
  621.     md3dDevice->CreateShaderResourceView(tileTex.Get(), &srvDesc, hDescriptor);
  622.  
  623.     // next descriptor
  624.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  625.  
  626.     srvDesc.Format = crateTex->GetDesc().Format;
  627.     srvDesc.Texture2D.MipLevels = crateTex->GetDesc().MipLevels;
  628.     md3dDevice->CreateShaderResourceView(crateTex.Get(), &srvDesc, hDescriptor);
  629.  
  630.     // next descriptor
  631.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  632.  
  633.     srvDesc.Format = iceTex->GetDesc().Format;
  634.     srvDesc.Texture2D.MipLevels = iceTex->GetDesc().MipLevels;
  635.     md3dDevice->CreateShaderResourceView(iceTex.Get(), &srvDesc, hDescriptor);
  636.  
  637.     // next descriptor
  638.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  639.  
  640.     srvDesc.Format = grassTex->GetDesc().Format;
  641.     srvDesc.Texture2D.MipLevels = grassTex->GetDesc().MipLevels;
  642.     md3dDevice->CreateShaderResourceView(grassTex.Get(), &srvDesc, hDescriptor);
  643.  
  644.     // next descriptor
  645.     hDescriptor.Offset(1, mCbvSrvDescriptorSize);
  646.  
  647.     srvDesc.Format = defaultTex->GetDesc().Format;
  648.     srvDesc.Texture2D.MipLevels = defaultTex->GetDesc().MipLevels;
  649.     md3dDevice->CreateShaderResourceView(defaultTex.Get(), &srvDesc, hDescriptor);
  650. }
  651.  
  652. void InstancingAndCullingApp::BuildShadersAndInputLayout()
  653. {
  654.     const D3D_SHADER_MACRO alphaTestDefines[] =
  655.     {
  656.         "ALPHA_TEST", "1",
  657.         NULL, NULL
  658.     };
  659.  
  660.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_1");
  661.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "PS", "ps_5_1");
  662.     
  663.     mInputLayout =
  664.     {
  665.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  666.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  667.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  668.     };
  669. }
  670.  
  671. void InstancingAndCullingApp::BuildSkullGeometry()
  672. {
  673.     std::ifstream fin("Models/skull.txt");
  674.  
  675.     if(!fin)
  676.     {
  677.         MessageBox(0, L"Models/skull.txt not found.", 0, 0);
  678.         return;
  679.     }
  680.  
  681.     UINT vcount = 0;
  682.     UINT tcount = 0;
  683.     std::string ignore;
  684.  
  685.     fin >> ignore >> vcount;
  686.     fin >> ignore >> tcount;
  687.     fin >> ignore >> ignore >> ignore >> ignore;
  688.  
  689.     XMFLOAT3 vMinf3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity);
  690.     XMFLOAT3 vMaxf3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity);
  691.  
  692.     XMVECTOR vMin = XMLoadFloat3(&vMinf3);
  693.     XMVECTOR vMax = XMLoadFloat3(&vMaxf3);
  694.  
  695.     std::vector<Vertex> vertices(vcount);
  696.     for(UINT i = 0; i < vcount; ++i)
  697.     {
  698.         fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
  699.         fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
  700.  
  701.         XMVECTOR P = XMLoadFloat3(&vertices[i].Pos);
  702.  
  703.         // Project point onto unit sphere and generate spherical texture coordinates.
  704.         XMFLOAT3 spherePos;
  705.         XMStoreFloat3(&spherePos, XMVector3Normalize(P));
  706.  
  707.         float theta = atan2f(spherePos.z, spherePos.x);
  708.  
  709.         // Put in [0, 2pi].
  710.         if(theta < 0.0f)
  711.             theta += XM_2PI;
  712.  
  713.         float phi = acosf(spherePos.y);
  714.  
  715.         float u = theta / (2.0f*XM_PI);
  716.         float v = phi / XM_PI;
  717.  
  718.         vertices[i].TexC = { u, v };
  719.  
  720.         vMin = XMVectorMin(vMin, P);
  721.         vMax = XMVectorMax(vMax, P);
  722.     }
  723.  
  724.     BoundingBox bounds;
  725.     XMStoreFloat3(&bounds.Center, 0.5f*(vMin + vMax));
  726.     XMStoreFloat3(&bounds.Extents, 0.5f*(vMax - vMin));
  727.  
  728.     fin >> ignore;
  729.     fin >> ignore;
  730.     fin >> ignore;
  731.  
  732.     std::vector<std::int32_t> indices(3 * tcount);
  733.     for(UINT i = 0; i < tcount; ++i)
  734.     {
  735.         fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
  736.     }
  737.  
  738.     fin.close();
  739.  
  740.     //
  741.     // Pack the indices of all the meshes into one index buffer.
  742.     //
  743.  
  744.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  745.  
  746.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::int32_t);
  747.  
  748.     auto geo = std::make_unique<MeshGeometry>();
  749.     geo->Name = "skullGeo";
  750.  
  751.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  752.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  753.  
  754.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  755.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  756.  
  757.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  758.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  759.  
  760.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  761.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  762.  
  763.     geo->VertexByteStride = sizeof(Vertex);
  764.     geo->VertexBufferByteSize = vbByteSize;
  765.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  766.     geo->IndexBufferByteSize = ibByteSize;
  767.  
  768.     SubmeshGeometry submesh;
  769.     submesh.IndexCount = (UINT)indices.size();
  770.     submesh.StartIndexLocation = 0;
  771.     submesh.BaseVertexLocation = 0;
  772.     submesh.Bounds = bounds;
  773.  
  774.     geo->DrawArgs["skull"] = submesh;
  775.  
  776.     mGeometries[geo->Name] = std::move(geo);
  777. }
  778.  
  779. void InstancingAndCullingApp::BuildPSOs()
  780. {
  781.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  782.  
  783.     //
  784.     // PSO for opaque objects.
  785.     //
  786.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  787.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  788.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  789.     opaquePsoDesc.VS = 
  790.     { 
  791.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  792.         mShaders["standardVS"]->GetBufferSize()
  793.     };
  794.     opaquePsoDesc.PS = 
  795.     { 
  796.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  797.         mShaders["opaquePS"]->GetBufferSize()
  798.     };
  799.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  800.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  801.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  802.     opaquePsoDesc.SampleMask = UINT_MAX;
  803.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  804.     opaquePsoDesc.NumRenderTargets = 1;
  805.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  806.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  807.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  808.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  809.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  810. }
  811.  
  812. void InstancingAndCullingApp::BuildFrameResources()
  813. {
  814.     for(int i = 0; i < gNumFrameResources; ++i)
  815.     {
  816.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  817.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  818.     }
  819. }
  820.  
  821. void InstancingAndCullingApp::BuildMaterials()
  822. {
  823.     auto bricks0 = std::make_unique<Material>();
  824.     bricks0->Name = "bricks0";
  825.     bricks0->MatCBIndex = 0;
  826.     bricks0->DiffuseSrvHeapIndex = 0;
  827.     bricks0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  828.     bricks0->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  829.     bricks0->Roughness = 0.1f;
  830.  
  831.     auto stone0 = std::make_unique<Material>();
  832.     stone0->Name = "stone0";
  833.     stone0->MatCBIndex = 1;
  834.     stone0->DiffuseSrvHeapIndex = 1;
  835.     stone0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  836.     stone0->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  837.     stone0->Roughness = 0.3f;
  838.  
  839.     auto tile0 = std::make_unique<Material>();
  840.     tile0->Name = "tile0";
  841.     tile0->MatCBIndex = 2;
  842.     tile0->DiffuseSrvHeapIndex = 2;
  843.     tile0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  844.     tile0->FresnelR0 = XMFLOAT3(0.02f, 0.02f, 0.02f);
  845.     tile0->Roughness = 0.3f;
  846.  
  847.     auto crate0 = std::make_unique<Material>();
  848.     crate0->Name = "checkboard0";
  849.     crate0->MatCBIndex = 3;
  850.     crate0->DiffuseSrvHeapIndex = 3;
  851.     crate0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  852.     crate0->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  853.     crate0->Roughness = 0.2f;
  854.  
  855.     auto ice0 = std::make_unique<Material>();
  856.     ice0->Name = "ice0";
  857.     ice0->MatCBIndex = 4;
  858.     ice0->DiffuseSrvHeapIndex = 4;
  859.     ice0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  860.     ice0->FresnelR0 = XMFLOAT3(0.1f, 0.1f, 0.1f);
  861.     ice0->Roughness = 0.0f;
  862.  
  863.     auto grass0 = std::make_unique<Material>();
  864.     grass0->Name = "grass0";
  865.     grass0->MatCBIndex = 5;
  866.     grass0->DiffuseSrvHeapIndex = 5;
  867.     grass0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  868.     grass0->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  869.     grass0->Roughness = 0.2f;
  870.  
  871.     auto skullMat = std::make_unique<Material>();
  872.     skullMat->Name = "skullMat";
  873.     skullMat->MatCBIndex = 6;
  874.     skullMat->DiffuseSrvHeapIndex = 6;
  875.     skullMat->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
  876.     skullMat->FresnelR0 = XMFLOAT3(0.05f, 0.05f, 0.05f);
  877.     skullMat->Roughness = 0.5f;
  878.     
  879.     mMaterials["bricks0"] = std::move(bricks0);
  880.     mMaterials["stone0"] = std::move(stone0);
  881.     mMaterials["tile0"] = std::move(tile0);
  882.     mMaterials["crate0"] = std::move(crate0);
  883.     mMaterials["ice0"] = std::move(ice0);
  884.     mMaterials["grass0"] = std::move(grass0);
  885.     mMaterials["skullMat"] = std::move(skullMat);
  886. }
  887.  
  888. void InstancingAndCullingApp::BuildRenderItems()
  889. {
  890.     auto skullRitem = std::make_unique<RenderItem>();
  891.     skullRitem->World = MathHelper::Identity4x4();
  892.     skullRitem->TexTransform = MathHelper::Identity4x4();
  893.     skullRitem->ObjCBIndex = 0;
  894.     skullRitem->Mat = mMaterials["tile0"].get();
  895.     skullRitem->Geo = mGeometries["skullGeo"].get();
  896.     skullRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  897.     skullRitem->InstanceCount = 0;
  898.     skullRitem->IndexCount = skullRitem->Geo->DrawArgs["skull"].IndexCount;
  899.     skullRitem->StartIndexLocation = skullRitem->Geo->DrawArgs["skull"].StartIndexLocation;
  900.     skullRitem->BaseVertexLocation = skullRitem->Geo->DrawArgs["skull"].BaseVertexLocation;
  901.     skullRitem->Bounds = skullRitem->Geo->DrawArgs["skull"].Bounds;
  902.  
  903.     // Generate instance data.
  904.     const int n = 5;
  905.     skullRitem->Instances.resize(n*n*n);
  906.  
  907.     float width = 200.0f;
  908.     float height = 200.0f;
  909.     float depth = 200.0f;
  910.  
  911.     float x = -0.5f*width;
  912.     float y = -0.5f*height;
  913.     float z = -0.5f*depth;
  914.     float dx = width / (n - 1);
  915.     float dy = height / (n - 1);
  916.     float dz = depth / (n - 1);
  917.     for(int k = 0; k < n; ++k)
  918.     {
  919.         for(int i = 0; i < n; ++i)
  920.         {
  921.             for(int j = 0; j < n; ++j)
  922.             {
  923.                 int index = k*n*n + i*n + j;
  924.                 // Position instanced along a 3D grid.
  925.                 skullRitem->Instances[index].World = XMFLOAT4X4(
  926.                     1.0f, 0.0f, 0.0f, 0.0f,
  927.                     0.0f, 1.0f, 0.0f, 0.0f,
  928.                     0.0f, 0.0f, 1.0f, 0.0f,
  929.                     x + j*dx, y + i*dy, z + k*dz, 1.0f);
  930.  
  931.                 XMStoreFloat4x4(&skullRitem->Instances[index].TexTransform, XMMatrixScaling(2.0f, 2.0f, 1.0f));
  932.                 skullRitem->Instances[index].MaterialIndex = index % mMaterials.size();
  933.             }
  934.         }
  935.     }
  936.  
  937.  
  938.     mAllRitems.push_back(std::move(skullRitem));
  939.     
  940.     // All the render items are opaque.
  941.     for(auto& e : mAllRitems)
  942.         mOpaqueRitems.push_back(e.get());
  943. }
  944.  
  945. void InstancingAndCullingApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  946. {
  947.     // For each render item...
  948.     for(size_t i = 0; i < ritems.size(); ++i)
  949.     {
  950.         auto ri = ritems[i];
  951.  
  952.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  953.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  954.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  955.  
  956.         // Set the instance buffer to use for this render-item.  For structured buffers, we can bypass 
  957.         // the heap and set as a root descriptor.
  958.         auto instanceBuffer = mCurrFrameResource->InstanceBuffer->Resource();
  959.         mCommandList->SetGraphicsRootShaderResourceView(0, instanceBuffer->GetGPUVirtualAddress());
  960.  
  961.         cmdList->DrawIndexedInstanced(ri->IndexCount, ri->InstanceCount, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  962.     }
  963. }
  964.  
  965. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> InstancingAndCullingApp::GetStaticSamplers()
  966. {
  967.     // Applications usually only need a handful of samplers.  So just define them all up front
  968.     // and keep them available as part of the root signature.  
  969.  
  970.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  971.         0, // shaderRegister
  972.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  973.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  974.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  975.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  976.  
  977.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  978.         1, // shaderRegister
  979.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  980.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  981.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  982.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  983.  
  984.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  985.         2, // shaderRegister
  986.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  987.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  988.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  989.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  990.  
  991.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  992.         3, // shaderRegister
  993.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  994.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  995.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  996.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  997.  
  998.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  999.         4, // shaderRegister
  1000.         D3D12_FILTER_ANISOTROPIC, // filter
  1001.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  1002.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  1003.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  1004.         0.0f,                             // mipLODBias
  1005.         8);                               // maxAnisotropy
  1006.  
  1007.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  1008.         5, // shaderRegister
  1009.         D3D12_FILTER_ANISOTROPIC, // filter
  1010.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  1011.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  1012.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  1013.         0.0f,                              // mipLODBias
  1014.         8);                                // maxAnisotropy
  1015.  
  1016.     return { 
  1017.         pointWrap, pointClamp,
  1018.         linearWrap, linearClamp, 
  1019.         anisotropicWrap, anisotropicClamp };
  1020. }
  1021.  
  1022.